#include "sync.h"
#include "interrupt.h"
#include "debug.h"

void sema_init(struct semaphore* psema, uint8_t value){
    psema->value = value;
    list_init(&psema->waiters);
}

void sema_down(struct semaphore* psema){
    enum intr_status old_status = intr_disable();
    while(psema->value == 0){  // 资源耗尽，尝试获取资源的线程（当前线程）需要等待 
        ASSERT(!list_elem_find(&psema->waiters, &running_thread()->general_tag));  // 当前线程不应该已经持有该信号量
        if(list_elem_find(&psema->waiters, &running_thread()->general_tag)){
            PANIC("sema_down: thread blocked has been in wait list\n");
        }
        list_append( &psema->waiters, &running_thread()->general_tag );
        thread_block(TASK_BLOCKED);
    }

    psema->value --;
    ASSERT(psema->value == 0); // 等待结束
    intr_set_status(old_status);
}

void sema_up(struct semaphore* psema){
    enum intr_status old_status = intr_disable();
    ASSERT(psema->value == 0);
    if( !list_is_empty(&psema->waiters) ){
        struct task_struct* thread_blocked = elem2entry(struct task_struct, general_tag, list_pop_front(&psema->waiters));
        thread_unblock(thread_blocked);
    }
    psema->value ++;
    ASSERT(psema->value == 1);
    intr_set_status(old_status);
}

void lock_init(struct lock* plock){
    plock->holder = NULL;
    plock->holder_repeat_nr = 0;
    sema_init(&plock->semaphore, 1);
}

void lock_acquire(struct lock* plock){
    if( plock->holder != running_thread() ){
        sema_down(&plock->semaphore);
        plock->holder = running_thread();
        ASSERT( plock->holder_repeat_nr == 0 );
        plock->holder_repeat_nr = 1;
    }else{  // 锁的持有者再次申请这把锁
        plock->holder_repeat_nr ++;
    }
}

void lock_release(struct lock* plock){
    ASSERT(plock->holder == running_thread());
    if( plock->holder_repeat_nr > 1 ){ plock->holder_repeat_nr--; return; }
    ASSERT(plock->holder_repeat_nr == 1);
    plock->holder = NULL;
    plock->holder_repeat_nr = 0;
    sema_up(&plock->semaphore);
}







